package pine.web.dao;

import java.io.Serializable;
import java.util.Collection;
import java.util.List;

import org.apache.log4j.Logger;
import org.hibernate.LockMode;
import org.hibernate.criterion.Criterion;
import org.hibernate.criterion.DetachedCriteria;
import org.hibernate.criterion.Projections;

import pine.web.common.grid.Pagination;

public abstract class AbstractHibernateDao<T> extends AbstractHibernateDaoSupport implements
		HibernateDao<T> {
	
	private Logger log = Logger.getLogger(AbstractHibernateDao.class);
	
	protected abstract Class<T> getEntityClass();

	@Override
	public T save(T entity) {
		getHibernateTemplate().saveOrUpdate(entity);
		return entity;
	};
	
	@Override
	public void saveAll(Collection<T> entities) {
		getHibernateTemplate().saveOrUpdateAll(entities);
	}
	
	@Override
	public T get(Serializable id) {
		return getHibernateTemplate().get(getEntityClass(), id);
	}
	
	@Override
	public T getWithLock(Serializable id, LockMode lock) {
		T t = getHibernateTemplate().get(getEntityClass(), id);;
		if (t != null) 
			flush();
		return t;
	}
	
	@Override
	public T merge(T entity) {
		getHibernateTemplate().merge(entity);
		return entity;
	};
	
	@Override
	public T evict(T entity) {
		getHibernateTemplate().evict(entity);
		return entity;
	};
	
	@Override
	public T load(Serializable id) {
		return getHibernateTemplate().load(getEntityClass(), id);
	}
	
	@Override
	public List<T> loadAll() {
		return getHibernateTemplate().loadAll(getEntityClass());
	}
	
	@Override
	public void remove(Serializable id) {
		T ob = load(id);
		if (ob == null) {
			if(log.isDebugEnabled())
				log.debug("can't delete entity by primary key:"+getEntityClass().getName()+"."+id+",object is not exist!");
			return;
		}
		getHibernateTemplate().delete(ob);
	}
	
	@Override
	public void remove(T t) {
		getHibernateTemplate().delete(t);
	}
	
	@Override
	public void remove(T t, org.hibernate.LockMode lockMode) {
		getHibernateTemplate().delete(t, lockMode);
	}
	
	@Override
	public void removeAll(Collection<T> entities) {
		getHibernateTemplate().deleteAll(entities);
	}
	
	@Override
	public void lock(T entity, LockMode lockMode) {
		getHibernateTemplate().lock(entity, lockMode);
	};
	
	@Override
	public void flush() {
		getHibernateTemplate().flush();
	}
	
	@SuppressWarnings("unchecked")
	@Override
	public List<T> findByExample(T t) {
		return getHibernateTemplate().findByExample(t);
	}
	
	@SuppressWarnings("unchecked")
	@Override
	public List<T> findByExample(T t, Integer start, Integer limit) {
		return getHibernateTemplate().findByExample(t, start, limit);
	}
	
	@Override
	public List<T> findByCriteria(Criterion... criterions) {
		return findByCriteria(null, null, criterions);
	}
	
	@SuppressWarnings("unchecked")
	@Override
	public List<T> findByCriteria(Integer firstResult, Integer maxResults,
			Criterion... criterions) {
		DetachedCriteria detachedCriteria = DetachedCriteria.forClass(getEntityClass());
		if (criterions !=null) {
			for (Criterion criterion : criterions) {
				detachedCriteria.add(criterion);
			}
		}
		if (firstResult == null || maxResults == null || maxResults == 0)
        	return getHibernateTemplate().findByCriteria(detachedCriteria);
    	else 
    		return getHibernateTemplate().findByCriteria(detachedCriteria, firstResult, maxResults);
	}
	
	@Override
	public long countByCriteria(Criterion... criterions) {
		DetachedCriteria detachedCriteria = DetachedCriteria.forClass(getEntityClass());
		if (criterions !=null) {
			for (Criterion criterion : criterions) {
				detachedCriteria.add(criterion);
			}
		}
		detachedCriteria.setProjection(Projections.rowCount());
		return (Long) getHibernateTemplate().findByCriteria(detachedCriteria).iterator().next();
	}
	
	@Override
	public Pagination<T> findPageByCriteria(Pagination<T> page,
			Criterion... criterions) {
		if (page == null) {
			page = new Pagination<T>();
		}
		List<T> rows = findByCriteria(page.getCurrentPageStartIndex(), page.getPageSize(), criterions);
		long total = countByCriteria(criterions);
		page.setRows(rows);
		page.setTotal(total);
		return page;
	}
	
}
